﻿import mx.utils.Delegate;
import caurina.transitions.Equations;
import caurina.transitions.Tweener;
import kliment.controls.ListBoxItemAbstract;
import kliment.display.MCC;
import kliment.geom.SimplePoint;
import kliment.utils.Queue;
import kliment.controls.Orientation;

/**
 * ...
 * @author	Kliment
 * @version	2.1.2
 */

class kliment.controls.ListBox {
	private static var cloneIndex:Number = 0;
	
	private var _itemRender:Function;
	private var _target_mc:MovieClip;
	private var _dataProvider:Array;
	private var _list:Array;
	private var _queue:Queue;
	private var _nextPosition:Number = 0;
	private var _nextId:Number = 0;
	private var _orientation:Object;
	private var _width:Number = 0;
	private var _height:Number = 0;
	private var _hInterval:Number = 0;
	private var _vInterval:Number = 0;
	private var _countColumn:Number = 1;
	private var _countRow:Number = 1;
	private var _widthColumn:Number;
	private var _widthRow:Number;
	private var _heigthColumn:Number;
	private var _heigthRow:Number;
	
	public var current:MovieClip;
	public var onUpdate:Function;
	public var animationUpdate:Boolean = false;
	
	public var sharedData:Object;
	
	public function ListBox(target_mc:MovieClip, orientation:Object) {
		_list = new Array();
		_target_mc = target_mc;
		_orientation = orientation;
		_queue = new Queue();
	}
	
	public function get itemRender() { return _itemRender }
	public function set itemRender(mc_identifer) {
		_itemRender = mc_identifer;
		if (_dataProvider)
			dataProvider = _dataProvider;
	}
	
	public function get dataProvider():Array { return _dataProvider }
	public function set dataProvider(value:Array):Void {
		_dataProvider = value;
		if (!_itemRender) return;
		erase();
		var len:Number = _dataProvider.length;
		for (var i:Number = 0; i < len; i++ ) 
			var item = add(_dataProvider[i]);
		_queue.start();
	}
	
	public function add(data:Object) {
		var newItem = new _itemRender(_target_mc);
		newItem.index = _list.length;
		newItem.data = data;
		newItem.sharedData = sharedData;
		newItem.host = this;
		newItem.translateTo(_getPosition(_list.length));
		_list.push(newItem);
		newItem.onCreated();
		
		_width = Math.max(_target_mc._width, _width);
		_height = Math.max(_target_mc._height ,_height);
	}
	
	public function remove(victim):Void {
		var target:ListBoxItemAbstract;
		if (victim instanceof ListBoxItemAbstract) {
			target = victim;
		} else if (victim >= 0) {
			target = _list[victim];
		} else {
			return;
		}
		
		var length:Number = _list.length;
		for (var i:Number = 0; i < length; ++i) {
			if (_list[i] == target) {
				Tweener.removeTweens(target);
				target.remove();
				_list.splice(i, 1);
				_updateFrom(i);
				break;
			}
		}
	}
	
	public function get currentIndex():Number {
		for (var i in _list) 
			if (_list[i] == current)
				return i;
		return -1;
	}
	
	public function getItem(index:Number):ListBoxItemAbstract {
		return _list[index];
	}
	
	public function update():Void {
		_updateFrom(0);
	}
	
	private function _updateFrom(index:Number):Void {
		var length:Number = _list.length;
		for (var i:Number = index; i < length; ++i) {
			var pos:SimplePoint = _getPosition(i);
			var item:ListBoxItemAbstract = _list[i];
			item.index = i;
			if (!animationUpdate) {
				item.translateTo(pos);
			} else {
				var parameters:Object = { x:pos.x, y:pos.y, time:.5, transition:Equations.easeOutCubic };
				if (i == index)
					parameters.onUpdate = Delegate.create(this, _onUpdateAnimationHandler);
				Tweener.addTween(item, parameters);
			}
		}
		onUpdate(this);
	}
	
	private function _onUpdateAnimationHandler():Void {
		onUpdate(this);
	}
	
	private function _getPosition(index:Number):SimplePoint {
		var result:SimplePoint;
		
		var nextX:Number = 0;
		var nextY:Number = 0;
		var length:Number = _list.length;
		for (var i:Number = 0; i < index; ++i) {
			var item:ListBoxItemAbstract = _list[i];
			nextX += item.width + _hInterval;
			nextY += item.height + _vInterval;
		}
		switch(_orientation) {
			case Orientation.HORIZONTAL:
				result = new SimplePoint(nextX , 0);
			break;
			
			case Orientation.VERTICAL:
				result = new SimplePoint(0, nextY);
			break;
			
			case Orientation.TILE:
				trace("mode don't work! use: Orientation.HORIZONTAL or Orientation.VERTICAL");
			break;
		}
		return result;
	}
	
	public function erase():Void {
		while (_list.length > 0) 
			_list.shift().remove();
		_nextId = 0;
		_queue.reset();
	}
	
	public function get queue():Queue { return _queue }
	
	public function get length():Number { return _list.length }
	
	public function get hInterval():Number { return _hInterval }
	public function set hInterval(value:Number):Void {
		_hInterval = value;
		update();
	}
	
	public function get vInterval():Number { return _vInterval }
	public function set vInterval(value:Number):Void {
		_vInterval = value;
		update();
	}
	
	public function get target_mc():MovieClip { return _target_mc }
	
	public function clone():ListBox {
		var clone_mc = _target_mc.duplicateMovieClip(_target_mc._name+"_clon-" + cloneIndex++, 10);
		var lb:ListBox  = new ListBox(clone_mc, _orientation, _width, _height);
		lb.itemRender = _itemRender;
		lb._countColumn = _countColumn;
		lb._countRow = _countRow;
		lb._hInterval = _hInterval;
		lb._vInterval = _vInterval;
		lb._widthColumn = _widthColumn;
		lb._widthRow = _widthRow;
		lb._heigthColumn = _heigthColumn;
		lb._heigthRow = _heigthRow;
		lb.dataProvider = _dataProvider;
		return lb;
	}
	
	public function get x():Number { return _target_mc._x }
	public function set x(value:Number):Void { 
		_target_mc._x = value;
	}
	
	public function get y():Number { return _target_mc._y }
	public function set y(value:Number):Void { 
		_target_mc._y = value;
	}
	
	public function get width():Number { return _width }
	public function set width(value:Number):Void {
		value = Math.max(1, value);
		_width = value;
		
		if (_orientation == Orientation.VERTICAL){
			var len:Number = _list.length;
			for (var i:Number = 0; i < len; i++) {
				_list[i].width = _width;
			}
			update();
		}
	}
	
	public function get height():Number { return _height }
	public function set height(value:Number):Void {
		value = Math.max(1, value);
		_height = value;
		
		if (_orientation == Orientation.HORIZONTAL){
			var len:Number = _list.length;
			for (var i:Number = 0; i < len; i++) {
				_list[i].height = _height;
			}
			update();
		}
	}
}